/*
 *  This file is part of LifeBudget - Copyright 2010 Clifton Eaton
 *  ------------------------------------------------------------------
 *  LifeBudget is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  LifeBudget is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with LifeBudget.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.lifebudget.app.persistence.repository;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;

import org.lifebudget.app.client.mvc.model.Category;
import org.lifebudget.app.client.mvc.model.PaycheckCalculator;
import org.lifebudget.app.client.mvc.model.Transaction;
import org.lifebudget.app.client.mvc.model.Transaction.TransactionType;
import org.lifebudget.app.misc.UserHelper;
import org.lifebudget.app.persistence.EMF;
import org.lifebudget.app.persistence.dao.TransactionDAO;
import org.lifebudget.app.persistence.dao.TransactionItemDAO;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;

/**
 * The Class TransactionRepository uses Data Access Objects and persists
 * them using JPA.  
 */
public class TransactionRepository {
	
	/** The emf. */
	private EntityManagerFactory emf;
	
	/** The cat repo. */
	private CategoryRepository catRepo;
	
	/** The pay repo. */
	private PaycheckCalculatorRepository payRepo;

	/**
	 * Instantiates a new transaction repository.
	 */
	public TransactionRepository() {
		this.emf = EMF.get();
		catRepo = new CategoryRepository();
		payRepo = new PaycheckCalculatorRepository();
	}

	/**
	 * Gets the all transactions.
	 *
	 * @return the all transactions
	 */
	public List<Transaction> getAllTransactions() {
		List<Transaction> transactions = new ArrayList<Transaction>();
		EntityManager em = emf.createEntityManager();
		try {
			Query q = em.createQuery("SELECT t FROM " + TransactionDAO.class.getName() + " t WHERE t.userId = ?1");
			q.setParameter(1, UserHelper.getUser().getUserId());
			List<TransactionDAO> pts = q.getResultList();
			for (TransactionDAO pt : pts) {
				transactions.add(pt.toModelObject());
			}
		} finally {
			em.close();
		}
		for (Transaction t : transactions) {
			if (t.getType() == TransactionType.Paycheck && t.getPaycheckCalc() != null) {
				// this may result in a null paycheck if it's been deleted
				PaycheckCalculator pc = payRepo.getPaycheckCalculator(t.getPaycheckCalc().getId());
				t.setPaycheckCalc(pc);
			} else if (t.getType() == TransactionType.Categorized && t.getCategory() != null) {
				Category c = catRepo.getCategory(t.getCategory().getId());
				t.setCategory(c);
			}

		}
		return transactions;
	}

	/**
	 * Adds the transaction.
	 *
	 * @param t the t
	 * @return the long
	 */
	public long addTransaction(Transaction t) {
		EntityManager em = emf.createEntityManager();
		long newId;
		try {
			TransactionDAO pt = new TransactionDAO(t);
			pt.setUserId(UserHelper.getUser().getUserId());
			em.persist(pt);
			em.refresh(pt);
			newId = pt.getKey().getId();
		} finally {
			em.close();
		}
		return newId;
	}

	/**
	 * Save transaction items.
	 *
	 * @param tItems the t items
	 */
	public void saveTransactionItems(List<TransactionItemDAO> tItems) {
		for (TransactionItemDAO ti : tItems) {
			saveTransactionItem(ti);
		}
	}

	/**
	 * Save transaction item.
	 *
	 * @param tItem the t item
	 */
	private void saveTransactionItem(TransactionItemDAO tItem) {
		EntityManager em = emf.createEntityManager();
		try {
			if (tItem.getUserId() == null) {
				tItem.setUserId(UserHelper.getUser().getUserId());
			}
			em.persist(tItem);
		} finally {
			em.close();
		}
	}

	/**
	 * Gets the transaction.
	 *
	 * @param transaction the transaction
	 * @return the transaction
	 */
	public TransactionDAO getTransaction(Transaction transaction) {
		TransactionDAO t = null;
		EntityManager em = emf.createEntityManager();
		try {
			Key key = KeyFactory.createKey(TransactionDAO.class.getSimpleName(), transaction.getId());
			t = em.find(TransactionDAO.class, key);
		} finally {
			em.close();
		}
		return t;
	}

	/**
	 * Update transaction.
	 *
	 * @param t the t
	 */
	public void updateTransaction(Transaction t) {
		EntityManager em = emf.createEntityManager();
		try {

			TransactionDAO pt = em.find(TransactionDAO.class, t.getId());
			pt.setFieldsFromModelObject(t);

		} finally {
			em.close();
		}
	}

	/**
	 * Removes the all transaction items for transaction.
	 *
	 * @param id the id
	 */
	public void removeAllTransactionItemsForTransaction(long id) {
		EntityManager em = emf.createEntityManager();
		try {
			Query q = em.createQuery("DELETE FROM " + TransactionItemDAO.class.getName()
					+ " ti WHERE ti.transactionId = ?1");
			q.setParameter(1, id);
			int num = q.executeUpdate();
			System.out.println("Deleted " + num + " TransactionItemDAO(s)");
		} finally {
			em.close();
		}
	}

	/**
	 * Delete transaction.
	 *
	 * @param transaction the transaction
	 */
	public void deleteTransaction(Transaction transaction) {
		if (transaction.getId() != 0) {
			EntityManager em = emf.createEntityManager();
			try {
				Key key = KeyFactory.createKey(TransactionDAO.class.getSimpleName(), transaction.getId());
				TransactionDAO pt = em.find(TransactionDAO.class, key);
				if (pt != null) {
					// remove it
					em.remove(pt);
				}
			} finally {
				em.close();
			}

		}

	}

	/**
	 * Gets the all transaction items for category.
	 *
	 * @param id the id
	 * @return the all transaction items for category
	 */
	public List<TransactionItemDAO> getallTransactionItemsForCategory(long id) {
		List<TransactionItemDAO> tItems = new ArrayList<TransactionItemDAO>();
		EntityManager em = emf.createEntityManager();
		try {
			Query q = em.createQuery("SELECT t FROM " + TransactionItemDAO.class.getName()
					+ " t WHERE t.categoryId = ?1");
			// q.setParameter(1, UserHelper.getUser().getUserId());
			q.setParameter(1, id);
			List<TransactionItemDAO> tis = q.getResultList();
			for (TransactionItemDAO ti : tis) {
				tItems.add(ti);
			}
		} finally {
			em.close();
		}
		return tItems;
	}

}
